from classes.Leilao import Leilao
from classes.ParametrosUsuario import ParametrosUsuario
from classes.Participante import Participante
import unittest

class TesteParticipante(unittest.TestCase):
    def setUp(self):
        self.parametrosParaPerfeitamenteRacionais = ParametrosUsuario()
        self.parametrosParaPerfeitamenteRacionais.distribuicaoDinheiroDisponivel = "normal"
        self.parametrosParaPerfeitamenteRacionais.distribuicaoValorParaParticipante = "normal"
        self.parametrosParaPerfeitamenteRacionais.numeroDeLeiloes = 1
        self.parametrosParaPerfeitamenteRacionais.numeroDeParticipantes = 10
        self.parametrosParaPerfeitamenteRacionais.parametrosDinheiroDisponivel = [400, 200]
        self.parametrosParaPerfeitamenteRacionais.parametrosValorParaParticipante = [400, 100]
        self.parametrosParaPerfeitamenteRacionais.perfeitamenteRacionais = True
        self.parametrosParaPerfeitamenteRacionais.valorRealDoProduto = 500
        self.parametrosParaPerfeitamenteRacionais.valorInicial = 50
        self.parametrosParaPerfeitamenteRacionais.aumentoMinimo = 25

        self.parametrosParaPerfisDiferentes = ParametrosUsuario()
        self.parametrosParaPerfisDiferentes.distribuicaoDinheiroDisponivel = "normal"
        self.parametrosParaPerfisDiferentes.distribuicaoValorParaParticipante = "normal"
        self.parametrosParaPerfisDiferentes.numeroDeLeiloes = 1
        self.parametrosParaPerfisDiferentes.numeroDeParticipantes = 10
        self.parametrosParaPerfisDiferentes.parametrosDinheiroDisponivel = [400, 200]
        self.parametrosParaPerfisDiferentes.parametrosValorParaParticipante = [400, 100]
        self.parametrosParaPerfisDiferentes.perfeitamenteRacionais = False
        self.parametrosParaPerfisDiferentes.valorRealDoProduto = 500
        self.parametrosParaPerfisDiferentes.valorInicial = 50
        self.parametrosParaPerfisDiferentes.aumentoMinimo = 25
        self.parametrosParaPerfisDiferentes.quantidadeDeParticipantesAgressivos = 3
        self.parametrosParaPerfisDiferentes.quantidadeDeParticipantesCautelosos = 2
        self.parametrosParaPerfisDiferentes.quantidadeDeParticipantesModerados = 5

    def testeGeraNumeroDistribuicaoNormal(self):
        parametros = ParametrosUsuario()
        parametros.distribuicaoDinheiroDisponivel = "normal"
        parametros.distribuicaoValorParaParticipante = "normal"
        parametros.parametrosDinheiroDisponivel = [400, 200]
        parametros.parametrosValorParaParticipante = [400, 100]

        participante = Participante(parametros)

        self.assertNotEqual(participante.dinheiroDisponivel, None)
        self.assertNotEqual(participante.valorParaParticipante, None)

    def testeGeraNumeroDistribuicaoUniforme(self):
        parametros = ParametrosUsuario()
        parametros.distribuicaoDinheiroDisponivel = "uniforme"
        parametros.distribuicaoValorParaParticipante = "uniforme"
        parametros.parametrosDinheiroDisponivel = [400, 200]
        parametros.parametrosValorParaParticipante = [400, 100]

        participante = Participante(parametros)

        print(participante.dinheiroDisponivel)
        print(participante.valorParaParticipante)

        self.assertNotEqual(participante.dinheiroDisponivel, None)
        self.assertNotEqual(participante.valorParaParticipante, None)

    def testeGeraNumeroDistribuicaoGamma(self):
        parametros = ParametrosUsuario()
        parametros.distribuicaoDinheiroDisponivel = "gamma"
        parametros.distribuicaoValorParaParticipante = "gamma"
        parametros.parametrosDinheiroDisponivel = [400, 200]
        parametros.parametrosValorParaParticipante = [400, 100]

        participante = Participante(parametros)

        print(participante.dinheiroDisponivel)
        print(participante.valorParaParticipante)

        self.assertNotEqual(participante.dinheiroDisponivel, None)
        self.assertNotEqual(participante.valorParaParticipante, None)

    def testeGeraNumeroDistribuicaoFixo(self):
        parametros = ParametrosUsuario()
        parametros.distribuicaoDinheiroDisponivel = "fixo"
        parametros.distribuicaoValorParaParticipante = "fixo"
        parametros.parametrosDinheiroDisponivel = [1000]
        parametros.parametrosValorParaParticipante = [2000]

        participante = Participante(parametros)

        self.assertEqual(participante.dinheiroDisponivel, 1000)
        self.assertEqual(participante.valorParaParticipante, 2000)

    def testeGeraNumeroDistribuicaoInexistente(self):
        parametros = ParametrosUsuario()
        parametros.distribuicaoDinheiroDisponivel = "teste"
        parametros.distribuicaoValorParaParticipante = "teste2"

        participante = Participante(parametros)

        self.assertEqual(participante.dinheiroDisponivel, None)
        self.assertEqual(participante.valorParaParticipante, None)

    def testeTempoDeResposta(self):
        parametros = ParametrosUsuario()
        parametros.distribuicaoDinheiroDisponivel = "fixo"
        parametros.distribuicaoValorParaParticipante = "fixo"
        parametros.parametrosDinheiroDisponivel = [1000]
        parametros.parametrosValorParaParticipante = [2000]

        participante = Participante(parametros)

        self.assertGreaterEqual(participante.tempoDeResposta, 1)
        self.assertLessEqual(participante.tempoDeResposta, 10)

    def testaSeParticipantesPerfeitamenteRacionaisAumentamOMinimo(self):
        leilao = Leilao(self.parametrosParaPerfeitamenteRacionais)

        lances = leilao.iniciaLeilao()
        lances = lances[0]

        for i in range(1, len(lances)):
            self.assertEqual(lances[i - 1] + leilao.aumentoMinimo, lances[i])

    def testaSeParticipantesPerfeitamenteRacionaisAumentamOMinimoQuandoOAumentoMinimoEZero(self):
        leilao = Leilao(self.parametrosParaPerfeitamenteRacionais)
        leilao.aumentoMinimo = 0

        lances = leilao.iniciaLeilao()
        lances = lances[0]

        for i in range(1, len(lances)):
            self.assertEqual(lances[i - 1] + 1, lances[i])

    def testaSeAFuncaoParaCalcularOfertaEDefinidaCorretamenteParaParticipantePerfeitamenteRacional(self):
        leilao = Leilao(self.parametrosParaPerfeitamenteRacionais)

        for participante in leilao.participantes:
            self.assertEqual(participante.funcaoParaCalcularOferta, participante.ofertaPerfeitamenteRacional)

    def testaSeAFuncaoParaCalcularOfertaEDefinidaCorretamenteParaParticipantesComPerfisDiferentes(self):
        leilao = Leilao(self.parametrosParaPerfisDiferentes)

        contadorCautelosos = 0
        contadorModerados = 0
        contadorAgressivos = 0

        for participante in leilao.participantes:
            if participante.funcaoParaCalcularOferta == participante.ofertaParaPerfilCauteloso:
                contadorCautelosos += 1
            elif participante.funcaoParaCalcularOferta == participante.ofertaParaPerfilModerado:
                contadorModerados += 1
            elif participante.funcaoParaCalcularOferta == participante.ofertaParaPerfilAgressivo:
                contadorAgressivos += 1

        self.assertEqual(contadorCautelosos, self.parametrosParaPerfisDiferentes.quantidadeDeParticipantesCautelosos)
        self.assertEqual(contadorModerados, self.parametrosParaPerfisDiferentes.quantidadeDeParticipantesModerados)
        self.assertEqual(contadorAgressivos, self.parametrosParaPerfisDiferentes.quantidadeDeParticipantesAgressivos)

    def testaOfertaInicialParaPerfilCauteloso(self):
        participante = Participante(self.parametrosParaPerfisDiferentes, perfil="cauteloso")
        participante.dinheiroDisponivel = 100
        participante.valorParaParticipante = 100

        oferta = participante.fazOferta(50, 0, 10)

        self.assertEqual(oferta, 50)

    def testaOfertaNormalParaPerfilCauteloso(self):
        participante = Participante(self.parametrosParaPerfisDiferentes, perfil="cauteloso")
        participante.dinheiroDisponivel = 200
        participante.valorParaParticipante = 200

        i = 0
        while i < 10:
            oferta = participante.fazOferta(50, 50, 10)
            self.assertGreaterEqual(oferta, 60)
            i += 1

    def testaDesistenciaParaPerfilCauteloso(self):
        participante = Participante(self.parametrosParaPerfisDiferentes, perfil="cauteloso")
        participante.dinheiroDisponivel = 50
        participante.valorParaParticipante = 50

        i = 0
        while i < 10:
            oferta = participante.fazOferta(50, 50, 10)
            self.assertEqual(oferta, False)
            i += 1

    def testaOfertaQuandoPertoDoValorParaParticipanteParaPerfilCauteloso(self):
        participante = Participante(self.parametrosParaPerfisDiferentes, perfil="cauteloso")
        participante.dinheiroDisponivel = 100
        participante.valorParaParticipante = 100

        i = 0
        while i < 10:
            oferta = participante.fazOferta(50, 80, 10)
            self.assertEqual(oferta, 90)
            i += 1

    def testaOfertaQuandoPertoDoValorParaParticipanteEAumentoMinimoEZeroParaParticipanteParaPerfilCauteloso(self):
        participante = Participante(self.parametrosParaPerfisDiferentes, perfil="cauteloso")
        participante.dinheiroDisponivel = 100
        participante.valorParaParticipante = 100

        i = 0
        while i < 10:
            oferta = participante.fazOferta(50, 80, 0)
            self.assertEqual(oferta, 81)
            i += 1

    def testaOfertaInicialParaPerfilModerado(self):
        participante = Participante(self.parametrosParaPerfisDiferentes, perfil="moderado")
        participante.dinheiroDisponivel = 100
        participante.valorParaParticipante = 100

        oferta = participante.fazOferta(50, 0, 10)

        self.assertEqual(oferta, 50)

    def testaOfertaNormalParaPerfilModerado(self):
        participante = Participante(self.parametrosParaPerfisDiferentes, perfil="moderado")
        participante.dinheiroDisponivel = 200
        participante.valorParaParticipante = 200

        i = 0
        while i < 10:
            oferta = participante.fazOferta(50, 50, 10)
            self.assertGreaterEqual(oferta, 60)
            i += 1

    def testaDesistenciaParaPerfilModerado(self):
        participante = Participante(self.parametrosParaPerfisDiferentes, perfil="moderado")
        participante.dinheiroDisponivel = 50
        participante.valorParaParticipante = 50

        i = 0
        while i < 10:
            oferta = participante.fazOferta(50, 50, 10)
            self.assertEqual(oferta, False)
            i += 1

    def testaOfertaInicialParaPerfilAgressivo(self):
        participante = Participante(self.parametrosParaPerfisDiferentes, perfil="agressivo")
        participante.dinheiroDisponivel = 100
        participante.valorParaParticipante = 100

        oferta = participante.fazOferta(50, 0, 10)

        self.assertEqual(oferta, 50)

    def testaOfertaNormalParaPerfilAgressivo(self):
        participante = Participante(self.parametrosParaPerfisDiferentes, perfil="agressivo")
        participante.dinheiroDisponivel = 200
        participante.valorParaParticipante = 200

        i = 0
        while i < 10:
            oferta = participante.fazOferta(50, 50, 10)
            self.assertGreaterEqual(oferta, 60)
            i += 1

    def testaDesistenciaParaPerfilAgressivo(self):
        participante = Participante(self.parametrosParaPerfisDiferentes, perfil="agressivo")
        participante.dinheiroDisponivel = 50
        participante.valorParaParticipante = 50

        i = 0
        while i < 10:
            oferta = participante.fazOferta(50, 50, 10)
            self.assertEqual(oferta, False)
            i += 1

    def testaOfertaQuandoPertoDoValorParaParticipanteParaPerfilAgressivo(self):
        participante = Participante(self.parametrosParaPerfisDiferentes, perfil="agressivo")
        participante.dinheiroDisponivel = 120
        participante.valorParaParticipante = 100

        i = 0
        while i < 10:
            oferta = participante.fazOferta(50, 80, 10)
            self.assertEqual(oferta, 100)
            i += 1

    def testaOfertaQuandoPertoDoValorParaParticipanteEDinheiroDisponivelMenorQueValorParaParticipanteParaPerfilAgressivo(self):
        participante = Participante(self.parametrosParaPerfisDiferentes, perfil="agressivo")
        participante.dinheiroDisponivel = 95
        participante.valorParaParticipante = 100

        i = 0
        while i < 10:
            oferta = participante.fazOferta(50, 80, 10)
            self.assertEqual(oferta, 95)
            i += 1

    def testaSeAsOfertasDosPerfisCautelosoModeradoEAgressivoSaoCrescentesEmMedia(self):
        participanteCauteloso = Participante(self.parametrosParaPerfisDiferentes, perfil="cauteloso")
        participanteCauteloso.dinheiroDisponivel = 1000
        participanteCauteloso.valorParaParticipante = 1000

        participanteModerado = Participante(self.parametrosParaPerfisDiferentes, perfil="moderado")
        participanteModerado.dinheiroDisponivel = 1000
        participanteModerado.valorParaParticipante = 1000

        participanteAgressivo = Participante(self.parametrosParaPerfisDiferentes, perfil="agressivo")
        participanteAgressivo.dinheiroDisponivel = 1000
        participanteAgressivo.valorParaParticipante = 1000

        contadorCauteloso = 0
        contadorModerado = 0
        contadorAgressivo = 0

        i = 0
        while i < 200:
            contadorCauteloso += participanteCauteloso.fazOferta(10, 100, 50)
            contadorModerado += participanteModerado.fazOferta(10, 100, 50)
            contadorAgressivo += participanteAgressivo.fazOferta(10, 100, 50)
            i += 1

        self.assertGreater(contadorAgressivo, contadorModerado)
        self.assertGreater(contadorModerado, contadorCauteloso)
